#include <iostream>
#include <unistd.h>
#include <cstring>
#include <string.h>
#include <vector>
#include <queue>
#include <pthread.h>
using namespace std;
template <int N = 5, class T=int>
class ThreadPool
{
public:
    ThreadPool(void)
        :_pool(N)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void Init(void)
    {
    }

    void Lock(void)
    {
        pthread_mutex_lock(&_mutex);
    }
    void Unlock(void)
    {
        pthread_mutex_unlock(&_mutex);
    }

    void Wait(void)
    {
        pthread_cond_wait(&_cond);
    }

    void Signal(void)
    {
        pthread_cond_signal(&_cond);
    }

    bool IsEmpty(void)
    {
        return _task.IsEmpty();
    }

    static void *Routine(void *arg)
    {
        ThreadPool<5,T> *ptr = static_cast<ThreadPool<5,T> *>(arg);
        cout << "I am running..." << endl;
        while (true)
        {
            ptr->Lock();
            while (ptr->IsEmpty())
            {
                ptr->Wait();
            }
            T t = _task.front();
            _task.pop();
            ptr->Unlock();
            t();
        }
    }

    void push(const T& data)
    {
        Lock();
        _task.push(data);
        Signal();
        Unlock();

    }


    void Start()
    {
        for (int i = 0; i < N; i++)
        {
            pthread_create(&(_pool[i]), nullptr, Routine, this);
        }
    }

private:
    vector<pthread_t> _pool;
    queue<T> _task;
    pthread_t_mutex_t _mutex;
    pthread_cond_t _cond;
};